package me.minecraft.mod.cobblemonbukkitevent.mixin;

import com.cobblemon.mod.common.api.battles.model.actor.BattleActor;
import com.cobblemon.mod.common.api.moves.MoveTemplate;
import com.cobblemon.mod.common.api.moves.Moves;
import com.cobblemon.mod.common.battles.*;
import com.cobblemon.mod.common.battles.actor.PlayerBattleActor;
import com.cobblemon.mod.common.battles.pokemon.BattlePokemon;
import com.cobblemon.mod.common.item.battle.BagItem;
import com.cobblemon.mod.common.net.messages.client.battle.BattleMakeChoicePacket;
import com.cobblemon.mod.common.net.messages.client.battle.BattleQueueRequestPacket;
import me.minecraft.mod.cobblemonbukkitevent.bukkit.EventFactory;
import me.minecraft.mod.cobblemonbukkitevent.bukkit.event.BattleForfeitEvent;
import me.minecraft.mod.cobblemonbukkitevent.bukkit.event.ItemUsedEvent;
import me.minecraft.mod.cobblemonbukkitevent.bukkit.event.MoveSelectedEvent;
import me.minecraft.mod.cobblemonbukkitevent.bukkit.event.PokemonSwitchStartEvent;
import org.spongepowered.asm.mixin.Mixin;
import org.spongepowered.asm.mixin.injection.At;
import org.spongepowered.asm.mixin.injection.Inject;
import org.spongepowered.asm.mixin.injection.callback.CallbackInfo;

import java.util.List;

/**
 * @author langle__
 * @version 1.0
 */
@Mixin(value = BattleActor.class, remap = false)
public class BattleActorMixin {

    @Inject(method = "forceChoose", at = @At("HEAD"), cancellable = true)
    public void forceChoose(ShowdownActionResponse response, CallbackInfo ci) {
        BattleActor actor = (BattleActor) (Object) this;
        if (!(actor instanceof PlayerBattleActor)) return;
        if (!(response instanceof BagItemActionResponse bagItemResponse)) return;

        ShowdownActionRequest request = actor.getRequest();
        if (request == null) return;

        BagItem bagItem = bagItemResponse.getBagItem();
        BattlePokemon target = bagItemResponse.getTarget();
        ItemUsedEvent itemUsedEvent = EventFactory.callItemUsedEvent(actor.battle, target, bagItem, false);
        if (itemUsedEvent.isCancelled()) {
            actor.getResponses().clear();
            actor.setMustChoose(true);
            actor.sendUpdate(new BattleQueueRequestPacket(request));
            actor.sendUpdate(new BattleMakeChoicePacket());
            ci.cancel();
        }
    }

    @Inject(method = "setActionResponses", at = @At("HEAD"), cancellable = true)
    public void setActionResponses(List<ShowdownActionResponse> responses, CallbackInfo ci) {
        BattleActor actor = (BattleActor) (Object) this;
        if (!(actor instanceof PlayerBattleActor)) return;

        ShowdownActionRequest request = actor.getRequest();
        if (request == null || request.getActive() == null) return;

        for (int i = 0; i < responses.size(); i++) {
            ShowdownActionResponse response = responses.get(i);
            BattlePokemon pokemon = actor.getActivePokemon().get(i).getBattlePokemon();
            if (pokemon == null) continue;

            if (response instanceof ForfeitActionResponse) {
                BattleForfeitEvent battleForfeitEvent = EventFactory.callBattleForfeitEvent(actor.battle, actor, pokemon, true);
                if (battleForfeitEvent.isCancelled()) {
                    actor.getResponses().clear();
                    actor.setMustChoose(true);
                    actor.sendUpdate(new BattleQueueRequestPacket(request));
                    actor.sendUpdate(new BattleMakeChoicePacket());
                    ci.cancel();
                    return;
                }
                EventFactory.callBattleForfeitEvent(actor.battle, actor, pokemon, false);
            } else if (response instanceof MoveActionResponse) {
                String moveName = ((MoveActionResponse) response).getMoveName();
                List<InBattleMove> moves = request.getActive().get(i).moves;
                InBattleMove inBattleMove = null;
                for (InBattleMove move : moves) {
                    if (move.id.equals(moveName)) {
                        inBattleMove = move;
                        break;
                    }
                }
                if (inBattleMove == null) continue;
                MoveTemplate template = Moves.INSTANCE.getByNameOrDummy(inBattleMove.move);
                MoveSelectedEvent moveSelectedEvent = EventFactory.callMoveSelectedEvent(actor.battle, pokemon, null, template);
                if (moveSelectedEvent.isCancelled()) {
                    actor.getResponses().clear();
                    actor.setMustChoose(true);
                    actor.sendUpdate(new BattleQueueRequestPacket(request));
                    actor.sendUpdate(new BattleMakeChoicePacket());
                    ci.cancel();
                    return;
                }
            } else if (response instanceof SwitchActionResponse) {
                String pokemonId = ((SwitchActionResponse) response).getNewPokemonId().toString();
                BattlePokemon newPokemon = null;
                for (BattlePokemon p : actor.getPokemonList()) {
                    if (p.getUuid().toString().equals(pokemonId)) {
                        newPokemon = p;
                        break;
                    }
                }
                if (newPokemon == null) continue;
                PokemonSwitchStartEvent startEvent = new PokemonSwitchStartEvent(actor.battle, actor, pokemon, newPokemon);
                if (startEvent.isCancelled()) {
                    actor.getResponses().clear();
                    actor.setMustChoose(true);
                    actor.sendUpdate(new BattleQueueRequestPacket(request));
                    actor.sendUpdate(new BattleMakeChoicePacket());
                    ci.cancel();
                    return;
                }
            }
        }
    }

}
